/*
 Copyright (C) 2006-2007 The OZI Project
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions, and the following disclaimer.
 
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions, and the disclaimer that follows 
    these conditions in the documentation and/or other materials 
    provided with the distribution.

 3. The name "OZI" must not be used to endorse or promote products
    derived from this software without prior written permission.  For
    written permission, please contact The OZI Project.
 
 4. Products derived from this software may not be called "OZI", nor
    may "OZI" appear in their name, without prior written permission
    from The OZI Project.
 
 In addition, we request (but do not require) that you include in the 
 end-user documentation provided with the redistribution and/or in the 
 software itself an acknowledgement equivalent to the following:

     "This product includes software developed by The OZI Project."


 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 This software consists of voluntary contributions made by many 
 individuals on behalf of The OZI Project and was originally 
 created by Matt Jezorek <mjezorek@bellsouth.net>.  
 */

package com.ozi.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.util.logging.Level;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamWriter;
import org.apache.log4j.Logger;

/**
 * Singleton class that deals with JAXB to translate XML to Objects and back
 * This class should never be used by the public
 * @version 0.1b
 * @author <a href="http://oziproject.org">OZI Project Team</a>
 */
public final class OZIMarshaller {
    private static Logger log = Logger.getLogger(OZIMarshaller.class);
    private static OZIMarshaller instance = new OZIMarshaller();
    private Unmarshaller jaxb_unmarshaller = null;
    private Marshaller jaxb_marshaller = null;
    
   /**
    * Internal constructor for the creation of a singleton
    */
    private OZIMarshaller() {
        log.info("OZIXml Engine starting up");
        try {
            JAXBContext jcontext = JAXBContext.newInstance(com.ozi.sif.objects.SIFMessage.class);
            this.jaxb_marshaller = jcontext.createMarshaller();
            this.jaxb_unmarshaller = jcontext.createUnmarshaller();
        } catch (JAXBException ex) {
            log.error(ex);
        } catch (Exception ex) {
            log.error(ex);
        }
        if (this.jaxb_marshaller == null || this.jaxb_unmarshaller == null) {
            try {
                log.error("Could not properly setup jaxb marshalling");
                throw (new Exception("Could not properly setup jaxb marshalling"));
            } catch (Exception ex) {
                log.error(ex);
            }
        }
        log.info("OZIXml Engine started");
    }
    
   /**
    * Returns an instance of the singleton class
    * @return the instance
    */
    public static OZIMarshaller getInstance() {
        return instance;
    }
    
   /**
    * 	Converts message to XML and serializes it down the stream
    * 
    * @param obj the object to be marshalled
    * @param out the output stream to be used 
    * @throws Exception
    */
    public void marshal(com.ozi.sif.objects.SIFMessage obj, OutputStream out) throws Exception {
    	this.jaxb_marshaller.marshal(obj,out);
    }
    
   /**
    * Helper method that facilitates marshalling an AbstracSIFMessage
    * @param msg the message to be marshaled
    * @param out the output stream to be used
    * @throws Exception
    */
    public void marshal(SIFMessage msg, OutputStream out) throws Exception {
    	this.marshal((com.ozi.sif.objects.SIFMessage) msg.getSIFObject(), out);
    }
    
   /**
    * Converts message from XML to a java object
    * 
    * @param is the input stream to be used
    * @return a SIFMessage primitive that represents the XML message 
    * @throws Exception
    */
    public SIFMessage unmarshal(InputStream is ) throws Exception {
    	SIFMessage msg = new SIFMessage(jaxb_unmarshaller.unmarshal(is));    
    	return(msg);
    }
    
    /**
     * This will enable the formating of a message as an XML string
     * @return do we want formated output
     */
    public boolean enableFormatedOutput() {
        log.info("enabled the format of XML output");
        try {
            this.jaxb_marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,Boolean.TRUE);
        } catch (PropertyException ex) {
            log.error(ex);
            return false;
        }
        return true;
    }
    
    /**
     * This will disable the formating of a message as an XML string
     * @return do we want formated output
     */
    public boolean disableFormatedOutput() {
        log.info("disabled the format of XML output");
        try {
            this.jaxb_marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,Boolean.FALSE);
        } catch (PropertyException ex) {
            log.error(ex);
            return false;
        }
        return true;
    }
    
}
